//#define __AVR_ATmega32__ 1

#include <stdlib.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/iom32.h> //Force eclipse to recognize this is a Mega32 device.
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <string.h>

#include <cdefs.h>

#include "uart.h"
#include "AVRcommon.h"
#include "spiProtocol.h"
#include "twimaster.h"
#include "twi_eeprom.h"
#include "Interface.h"


#if (TERMINAL_BRAYS)
#define uart_clr() uart_putc(0x02); _delay_ms(200)
#else
#define uart_clr() uart_puts_P("\n\r\n\r\n\r")
#endif

#define uart_output_warn(s) uart_output(s)
#define uart_output_note(s) uart_output(s)

#define console_out_P(_s) uart_puts_P("\n\r[AVRs] "); uart_puts_P(_s)
#define console_out(s) uart_puts_P("\n\r[AVRs] "); uart_puts(s)

uint8_t ExternalClockStatus = 0;

void DumpPage(unsigned int PageNo)
{
	unsigned int i;

	PageNo = (PageNo*8); //Read page number
	if(checkTargetCommunication())
	{
		for(i=(PageNo);i<((PageNo)+8);i++)
		{
			uart_puthex_16byte(readProgramMemory(i));
			_delay_ms(200);
		}
	}
	else
	{
		console_out_P("ERROR: Communication Link Read Failure in DumpPage(ui)...");
	}
}

int main(void)
{
    unsigned int c;
    unsigned int i,b=0,CurrentByte=0,fudge=0;

    char vTmpString[255];
	char vTmpBuffer[16];

    uint8_t vTmpByte = 0;
    uint16_t vTmpLong = 0;
    double vTmpDouble = 0;

	uint8_t vGetByte[255];
	uint16_t vGetLong[255];
	uint32_t vGetDouble[255];

	EXIT_SAFEMODE_LED_READY;
	i2c_init();
    uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));

    sei();

    uart_clr();

	sprintf(vTmpString,"** %s [VERSION: %s.%s - BUILD: %s @ %s]",_APP_TITLE_,_APP_VER_,_APP_REV_,__DATE__,__TIME__);
	console_out(vTmpString);
	sprintf(vTmpString,"** Hardware v%s %s @ %sMhz - U(S)ART Communication v%s",_HARD_REV_,M_CPU,S_CPU,_UART_VER_);
	console_out(vTmpString);
	console_out_P(" ");
	sprintf(vTmpString,"** Welcome, User. System has been initialized and ready for use...");
	console_out(vTmpString);
	console_out_P(" ");
	sprintf(vTmpString,"System is in safe mode. Send '%c' to begin...",(unsigned char)EXIT_SAFEMODE_CHAR);
	console_out(vTmpString);

	// Safe mode loop.
	while(uart_getc() != (unsigned char)EXIT_SAFEMODE_CHAR)
	{
		EXIT_SAFEMODE_LED_OFF;
	}
	EXIT_SAFEMODE_LED_ON; //Turn on the Safemode led to tell user SAFEMODE IS OFF.
	console_out_P("System has exited safe mode. Functions are now available...");

    for(;;)
    {

        c = uart_getc();
        if ( c & UART_NO_DATA )
        {
        }
        else
        {


            if ( c & UART_FRAME_ERROR )
            {
            	console_out_P("XX>> UART Frame Error! ");
				break;
            }
            if ( c & UART_OVERRUN_ERROR )
            {
            	console_out_P("XX>> UART Overrun Error!");
				break;
            }
            if ( c & UART_BUFFER_OVERFLOW )
            {
            	console_out_P("XX>> Buffer Overflow Error!");
				break;
            }
            uart_clr();
            //console_out_P(" ");
			sprintf(vTmpString,"Received \"%c\", Looking up function...", c);
			console_out(vTmpString);
			console_out_P(" ");


			/* **************** CMD_TARGET_INFO ********************* */
			if ( c == (unsigned char)CMD_TARGET_INFO)
			{
				spiInitialize();

				console_out_P("Checking for response from target...");
				console_out_P(" ");
				if(checkTargetCommunication())
				{
					console_out_P("Received response from target, gathering data...");
					_delay_ms(200);
					console_out_P(" ");

					sprintf(vTmpString,"DeviceID: \t%02X %02X %02X",readSignatureByte(0),readSignatureByte(1),readSignatureByte(2));
					console_out(vTmpString);
					_delay_ms(200);

					if(readSignatureByte(1)+readSignatureByte(2) == 155)
					{
						console_out_P("TrgtName: \tAttiny2313");
					} else {
						console_out_P("TrgtName: \tUnknown");
					}
					_delay_ms(200);

					if(readProgramMemory(0) != 0xFFFF)
					{
						console_out_P("ProgStat: \tTarget IS currently programmed.");
					}
					else
					{
						console_out_P("ProgStat: \tTarget is NOT currently programmed.");
					}

					sprintf(vTmpString,"EPrmStat: \t%02X",(int)readEEPROM(0,vTmpByte));
					console_out(vTmpString);

					if(vTmpByte == 0)
					{
						printf(":EMPTY");
					}
					else
					{
						printf(":WRITTEN");
					}
					vTmpByte = 0;
					_delay_ms(200);

					sprintf(vTmpString,"LockByte: \t%02X",readLockByte());
					console_out(vTmpString);
					_delay_ms(200);

					sprintf(vTmpString,"   lFuse: \t%02X",readFuseLowByte());
					console_out(vTmpString);
					_delay_ms(200);

					sprintf(vTmpString,"   hFuse: \t%02X",readFuseHighByte());
					console_out(vTmpString);
					_delay_ms(200);

					sprintf(vTmpString,"  exFuse: \t%02X",readExtendedFuseByte());
					console_out(vTmpString);
					_delay_ms(200);

					sprintf(vTmpString,"CaliByte: \t%02X",readCalibrationByte());
					console_out(vTmpString);
					console_out_P(" ");
					resetTarget();
				}
				else
				{
					console_out_P("! Error: No response from target.");
					console_out_P("Quitting...");
				}
				console_out_P("Done."); //readCalibrationByte readLockByte
			}


			/* **************** CMD_TARGET_MEMDUMP ********************* */
			else if ( c == (unsigned char)CMD_TARGET_MEMDUMP)
			{
				uart_puts_P("Dumping 5 pages starting at 0:\n\r");
				vTmpByte = 0;
				for(i=0;i<5;i++)
				{
					//printf(":10%04X00",(i*16));
					DumpPage(i);
					uart_puts_P("\n\r");
					_delay_ms(150);
				}
				releaseTargetControl();

			}

			/* **************** CMD_TARGET_ERASE ********************* */
			else if ( c == (unsigned char)CMD_TARGET_ERASE)
			{
				if(checkTargetCommunication())
				{
					activateTargetControl();
					eraseChip();
					console_out_P("Chip Erased...");
				}
			}


			/* **************** CMD_EEPROM_DUMP ********************* */
			else if ( c == (unsigned char)CMD_EEPROM_DUMP)
			{
				console_out_P("External EEPROM Test...");
				console_out_P(" ");
				vTmpLong = 0;
				for(i=0;i<160;i++)
				{
					vTmpByte = eeprom_rd_byte(EEPROM_ID,i);
					printf("%02X ",vTmpByte);
					if(vTmpByte != 0xFF || vTmpByte != 0x00)
						vTmpLong = 1;
					_delay_ms(25);
				}
				console_out_P("EEPROM Dump Complete...");
				if(vTmpLong == 1)
					uart_puts_P(" EEPROM OK.");
				else
					uart_puts_P(" EEPROM MAY HAVE FAILED TEST.");
				console_out_P(" ");
			}


			/* **************** CMD_PROG_TARGET ********************* */
			else if ( c == (unsigned char)CMD_PROG_TARGET)
			{
				i=0;
				activateTargetControl();
				if(checkTargetCommunication())
				{
					vTmpByte = eraseChip();
					printf("Chip Erase: %02X", vTmpByte);
					vTmpByte=0;
					activateTargetControl();
					if(checkTargetCommunication())
					{
						performPageWrite(0);
						i=0;
						b=0;
						CurrentByte = 0;
						if(eeprom_rd_byte(DEVICE_ID,0) == 0xFF && eeprom_rd_byte(DEVICE_ID,1) == 0xFF)
						{
							uart_puts_P("EEPROM EMPTY, QUITTING...");
							break;
						}
						for(;;)
						{
							vTmpLong = eeprom_rd_byte(DEVICE_ID,CurrentByte);
							CurrentByte++;
							vTmpLong <<= 8;
							vTmpLong |= eeprom_rd_byte(DEVICE_ID,CurrentByte);
							CurrentByte++;

							if(vTmpLong == 0x0303 || vTmpLong == 0x03FF)
							{
								performPageWrite(fudge);
								//printf("> performPageWrite(%d)\n\r",fudge);
								break;
							}

							loadProgramMemoryPage(i,vTmpLong);
							//printf("LoadProgramMemorypage(%d,%04X) [L %d]\n\r",i,vTmpLong,b);
							_delay_ms(2);
							i++; b++;
							if(i==16)
							{
								performPageWrite(b-16);
								//printf("> performPageWrite(%d)\n\r",b-16);
								i=0;
								fudge = (b);
								_delay_ms(4);
							}

						}
						sprintf(vTmpString,"Wrote to page %02X a total of %04X bytes", fudge,CurrentByte);
						console_out(vTmpString);
						console_out_P("Programming Finished...");
					}
					else
					{
						console_out_P("Chip Erased. but communication failed...");
					}
				}
				else
				{
					console_out_P("Failed attempt. No communication.");
				}
				releaseTargetControl();
				resetTarget();

			}


			/* **************** CMD_HELP ********************* */
			else if ( c == (unsigned char)CMD_HELP)
			{
				console_out_P("Entering the help menu. ->\n\r");
				for(i=0; i<(sizeof(help)/2); i++){
					printf("[HELP]\t%c - %s\n\r",(unsigned int)cmds[i],help[i]);
				}
				uart_puts_P("[HELP]");
				console_out_P("[END OF HELP]");
			}


			/* **************** CMD_EXTERNAL_CLOCK ********************* */
			else if ( c == (unsigned char)CMD_EXTERNAL_CLOCK)
			{
				console_out_P("External Clock");
				if(ExternalClockStatus)
				{
					ExternalClockStatus = 0;
					EXTERNAL_CLOCK_OFF;
					console_out_P("External Clock OFF");
				} else {
					ExternalClockStatus = 1;
					EXTERNAL_CLOCK_ON;
					console_out_P("External Clock ON");
				}
			}


			/* **************** CMD_EEPROM_ERASE ********************* */
			else if ( c == (unsigned char)CMD_EEPROM_ERASE)
			{
				console_out_P("Erasing external EEPROM.\n\t");
				console_out_P("This may take a while, please wait... (11 #'s)");
				console_out_P("ERASE [");
				b=0;
				for(i=0; i<(DEVICE_MAX); i++){
					eeprom_wr_byte(DEVICE_ID,0xFF,i);
					b++;
					_delay_ms(5);
					if(b >= 3072)
					{
						uart_puts_P("#");
						b=0;
					}
				}
				uart_puts_P("] 100%");
				console_out_P("External EEPROM Erased.");
			}

			/* **************** CMD_FILL_EEPROM ********************* */
			else if ( c == (unsigned char)CMD_FILL_EEPROM)
			{
				console_out_P("Begin External EEPROM Fill Mode. (0x03 [EOT])\n\r>>");
				i=0;
				b=0;
				for(;;)
				{
					c = uart_getc();
			        if ( c & UART_NO_DATA )
			        	nop();
			        else
			        {
			        	if(c == 0x03)
			        	{
			        		b=1;
			        		break;
			        	}
			        	eeprom_wr_byte(DEVICE_ID,(uint8_t)c,i);
			        	i++;
			        	uart_putc((unsigned char)'*');
			        }
			        if(b)
			        	break;
				}
				sprintf(vTmpString,"External EEPROM Fill Completed. Length: %d bytes",i);
				console_out(vTmpString);
				console_out_P("Filling an extra 32 bytes blank.");
				eeprom_wr_byte(DEVICE_ID,0x03,i);
				i++;
				eeprom_wr_byte(DEVICE_ID,0x03,i);
				i++;
				for(b=0;b<32;b++)
				{
					eeprom_wr_byte(DEVICE_ID,0xFF,i+b);
				}
			}
			else
			{
				console_out("No function found. Quitting...");
			}
		}
    }
    return 0;
}
